﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;

namespace AutumnEngine.Editor
{
    public enum NodeType
    {
        Marker,
        Sprite,
        Animated,
        Physic,
        PhysicAnimated,
        Label,
        Button
    }

    public class EditorGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Vector2 size;

        public bool IsEnabled = true;

        Vector2 textureHalfSize = Vector2.Zero;

        string texture = "";
        Texture2D tex2d;

        public Scene GameScene;

        public NodeType Type
        {
            get;
            set;
        }

        public void Resize(int x, int y)
        {
            Engine.Modules.GraphicsManager.Resolution = new Vector2(x,y);
        }

        public void SetNewTexture(string text)
        {
            Texture = text;
        }

        public void SetNewFont(string font)
        {
            Font = font;
        }

        string sele = "";
        public string SelectedNodeName
        {
            get { return sele; }
            set
            {
                sele = value;
                Program.f.ChangeSelected();
            }
        }

        public Node SelectedNode
        {
            get 
            {
                if (sele != "")
                    return GameScene.Nodes[sele];
                else
                {
                    return null;
                }
            }
        }

        public string Texture
        {
            get { return texture; }
            set
            {
                texture = value;
                if (texture != "")
                    tex2d = Engine.Modules.TextureManager.GetTexture(texture);
                else
                    tex2d = Engine.Modules.TextureManager.Blank;

                textureHalfSize = new Vector2(tex2d.Width / 2, tex2d.Height / 2);
            }
        }

        string _font = "";
        SpriteFont sFont;
        public string Font
        {
            get { return _font; }
            set
            {
                _font = value;
                if (_font != "")
                    sFont = Engine.Modules.FontManager.GetFont(_font);
                else
                    sFont = Engine.Modules.FontManager.EngineFont;

                textureHalfSize = new Vector2(tex2d.Width / 2, tex2d.Height / 2);
            }
        }

        public void Save(string path)
        {
            GameScene.Save(path);
        }

        public void Load(string path)
        {
            sele = "";
            Engine.Modules.TextureManager.ClearAllNonEngineAssets();
            Engine.Modules.FontManager.ClearAllNonEngineAssets();
            //Add the default assets back in editor
            Program.f.AddDefaultAssetsAndClear();
            GameScene.Load(path);
        }

        public void AddTexture(string name, string path)
        {
            Engine.Modules.TextureManager.AddTexture(name, path);
        }
        public void AddFont(string name, string path)
        {
            Engine.Modules.FontManager.AddFont(name, path);
        }

        public EditorGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        public void PreViewerAdd(int width, int height)
        {
            size = new Vector2(width, height);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
           
            base.Initialize();
        }
        protected override void OnActivated(object sender, EventArgs args)
        {
            this.IsEnabled = true;
            base.OnActivated(sender, args);
        }

        protected override void OnDeactivated(object sender, EventArgs args)
        {
            this.IsEnabled = false;
            base.OnDeactivated(sender, args);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //Control modules not to be loaded.
            List<string> disabled = new List<string>();            
            Engine.Initialize(this, graphics,disabled);
            Engine.Modules.GraphicsManager.Resolution = size;            
            Texture = "Blank";
            Font = "Engine";
            GameScene = new Scene();
            Engine.Modules.SceneManager.AddScene("GameScene", GameScene);
            Engine.Modules.TextureManager.ClearAllNonEngineAssets();
            Engine.Modules.FontManager.ClearAllNonEngineAssets();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
        }

        public void SetSelectedNode(string name)
        {
            sele = name;
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            Engine.Update(gameTime);
            bool add = false;
            string name = "";
            if(Program.f.props.Focused == false)
            if (IsEnabled)
                if (Engine.Modules.MouseInput.IsLeftButtonTriggered)
                {
                    switch (Type)
                    {
                        case NodeType.Marker:
                            {
                                Marker tmp = new Marker();
                                tmp.Position = Engine.Modules.MouseInput.TransformedPosition;
                                 name = "Marker " + (DateTime.Now.Millisecond.ToString()).GetHashCode().ToString();
                                bool solved = false;
                                while (!solved)
                                {
                                    if (GameScene.Nodes.ContainsKey(name))
                                    {
                                        name += "9";
                                    }
                                    else
                                    {
                                        solved = true;
                                    }
                                }
                                GameScene.AddNode(name, tmp);
                                SelectedNodeName = name;
                                add = true;
                                break;
                            }
                        case NodeType.Sprite:
                            {
                                SpriteNode tmp = new SpriteNode(Texture);
                                tmp.CameraTranslation = true;
                                tmp.Origin = new Vector2(tex2d.Width / 2, tex2d.Height / 2);
                                tmp.Position = Engine.Modules.MouseInput.TransformedPosition;
                                name = "Sprite " + (DateTime.Now.Millisecond.ToString()).GetHashCode().ToString();
                                bool solved = false;
                                while (!solved)
                                {
                                    if (GameScene.Nodes.ContainsKey(name))
                                    {
                                        name += "9";
                                    }
                                    else
                                    {
                                        solved = true;
                                    }
                                }
                                GameScene.AddNode(name, tmp);
                                SelectedNodeName = name;
                                add = true;
                                break;
                            }
                        case NodeType.Label:
                            {
                                LabelNode la = new LabelNode(Font);
                                la.CameraTranslation = true;
                                la.Color = Color.White;
                                la.Position = Engine.Modules.MouseInput.TransformedPosition;
                                la.Text = "abc";
                                name = "Label " + (DateTime.Now.Millisecond.ToString()).GetHashCode().ToString();
                                bool solved = false;
                                while (!solved)
                                {
                                    if (GameScene.Nodes.ContainsKey(name))
                                    {
                                        name += "9";
                                    }
                                    else
                                    {
                                        solved = true;
                                    }
                                }
                                GameScene.AddNode(name, la);
                                SelectedNodeName = name;
                                add = true;
                                break;
                            }
                        case NodeType.Physic:
                            {
                                PhysicsSpriteNode tmp = new PhysicsSpriteNode(Texture, BodyType.Automatic, tex2d.Width, tex2d.Height, 10f);
                                tmp.CameraTranslation = true;
                                tmp.Color = Color.White;
                                tmp.Position = Engine.Modules.MouseInput.TransformedPosition;
                                name = "PhysicsObject " + (DateTime.Now.Millisecond.ToString()).GetHashCode().ToString();
                                bool solved = false;
                                while (!solved)
                                {
                                    if (GameScene.Nodes.ContainsKey(name))
                                    {
                                        name += "9";
                                    }
                                    else
                                    {
                                        solved = true;
                                    }
                                }
                                GameScene.AddNode(name, tmp);
                                SelectedNodeName = name;
                                add = true;
                                break;
                            }
                    }

                    if (add)
                    {
                        Program.f.NodeAdded(name);
                    }
                }
            base.Update(gameTime);
        }

        public void DeleteSelectedNode()
        {
            string t = sele;
            Program.f.DeletedNode(t);
            this.GameScene.Nodes.Remove(t);
            sele = "";

        }

        public void DeleteAllNodes()
        {
            sele = "";
            this.GameScene.Nodes.Clear();
        }

        public void DeleteNode(string name)
        {
            if (name == sele)
                DeleteSelectedNode();
            else
            {
                this.GameScene.Nodes.Remove(name);
                Program.f.DeletedNode(name);
            }
        }

         Color highlight = new Color(Color.HotPink, 150);

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            Engine.Draw();
            spriteBatch.Begin();
            //Draw the selected node.
            Engine.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront, SaveStateMode.None, GameScene.Camera.CameraMatrix);
            if (SelectedNode != null)
            {
               System.Diagnostics.Debug.WriteLine("Drawing");
               if (SelectedNode.GetType() == typeof(Marker))
               {
                   Engine.SpriteBatch.Draw(Engine.Modules.TextureManager.Blank, SelectedNode.Position, highlight);
               }
               else if (SelectedNode.GetType() == typeof(SpriteNode))
               {
                   SpriteNode n = SelectedNode as SpriteNode;
                   Color tmp = n.Color;
                   n.Color = highlight;
                   n.CameraTranslation = true;
                   n.Draw();
                   n.Color = tmp;                   
               }
               else if (SelectedNode.GetType() == typeof(PhysicsSpriteNode))
               {
                   PhysicsSpriteNode n = SelectedNode as PhysicsSpriteNode;
                   Color tmp = n.Color;
                   n.Color = highlight;
                   n.CameraTranslation = true;
                   n.Draw();
                   n.Color = tmp;
               }

               else if (SelectedNode.GetType() == typeof(LabelNode))
               {
                   LabelNode n = SelectedNode as LabelNode;
                   Color tmp = n.Color;
                   n.Color = highlight;
                   n.CameraTranslation = true;
                   n.Draw();
                   n.Color = tmp;
               }
               
           }
            
            //Draw the placement model.
            if (IsEnabled)
            {
                if (Type != NodeType.Label)
                {
                    Vector2 finalPos = Engine.Modules.MouseInput.NoneTransformedPosition - textureHalfSize;
                    spriteBatch.Draw(tex2d, finalPos, new Color(Color.HotPink, 100));
                }
                else
                {
                    Vector2 finalPos = Engine.Modules.MouseInput.NoneTransformedPosition - textureHalfSize;
                    spriteBatch.DrawString(sFont, "abc", finalPos, new Color(Color.HotPink, 100));
                }
            }
            Engine.SpriteBatch.End();
            spriteBatch.End();
            try
            {
                base.Draw(gameTime);
            }
            catch (InvalidOperationException)
            {

            }
        }
    }
}
